/* -*-C-*-
 ##############################################################################
 #
 # File:        trice/src/testtrig.c
 # RCS:         "@(#)$Revision: 1.20 $ $Date: 94/03/09 11:16:23 $"
 # Description: User routine for doing self test of E1430 module triggers
 # Author:      Doug Passey
 # Created:     
 # Language:    C
 # Package:     E1430
 # Status:      "@(#)$State: Exp $"
 #
 # (C) Copyright 1992, Hewlett-Packard Company, all rights reserved.
 #
 ##############################################################################
 #
 # Please add additional comments here
 #
 # Revisions:
 #
 ##############################################################################
*/

#    include <stdio.h>
#    include <math.h>

#include "trice.h"
#include "err1430.h"

#ifndef lint
const char i1430_testtrig_fileId[] = "$Header: testtrig.c,v 1.20 94/03/09 11:16:23 chriss Exp $";
#endif

#define TEST_RANGE	0.0625
#define TEST_BLOCK_SIZE		128
#define MIN_OFFSET	0.015625
#define MAX_OFFSET	0.046875
#define NUM_DELAYS	3
#ifdef _FIRST_PROTOS_
#define HYSTERESIS_BITS	3
#else
#define HYSTERESIS_BITS	1
#endif

/*****************************************************************************
 *
 * Slope trigger test.  
 *
 ****************************************************************************/
static SHORTSIZ16 check_slope_trigger(SHORTSIZ16 groupID, SHORTSIZ16 trigMode,
	FLOATSIZ64 trigLevel, SHORTSIZ16 trigSlope, SHORTSIZ16 offset, 
	SHORTSIZ16 *triggered)
{
  SHORTSIZ16 error, status, la;
  char buf[80];

  error = i1430_get_first_la(groupID, &la);
  if(error) return(error);

  sprintf(buf, "%d", (LONGSIZ32)la);

  error = e1430_set_trigger_mode(groupID, trigMode, 0L, trigLevel, trigSlope); 
  if(error) return(error);

  e1430_pause(0.1);

  error = e1430_arm_module(groupID);
  if(e1430_device_clear_flag) return(0);	/* SCPI issued a device clear */
  if(error) return(error);

  error = e1430_write_register_image(la, E1430_INPUT_OFFSET_REG, offset);
  if(error) return(error);
  
  e1430_pause(0.1);

  error = e1430_get_status(la, &status);
  if(error) return(error);

  if(status & E1430_MEAS_STATUS_OVERLOAD) {
    return(i1430_Error(ERR1430_ADC_OVERLOAD, buf, NULL));
  }

  if(status & E1430_MEAS_STATUS_ADC_ERROR) {
    return(i1430_Error(ERR1430_ADC_ERROR, buf, NULL));
  }

  if((status & E1430_MEAS_STATUS_STATE_MASK) == E1430_MEAS_STATUS_TRIG_STATE) {
    *triggered = 0;
  }else{
    *triggered = 1;
  }

  return(0);
}


  
/*****************************************************************************
 *
 * Test triggering.   Check simple triggering in ADC and MAG triggering mode.
 * Use offset DAC to move ADC thru a trigger point.  Check to see if triggering
 * occurs for both positive and negative slope, and doesn't occur when the
 * slope crossing the trigger point is wrong.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_test_trigger(SHORTSIZ16 la)
{
  FLOATSIZ64 val0x400, val0xC00;
  SHORTSIZ16 error, data, i, j, k; 
  volatile SHORTSIZ16 x, y, firstx, firsty;
  volatile USHORTSIZ16 *addr;
  SHORTSIZ16 groupID;
  SHORTSIZ16 triggered;
  FLOATSIZ32 buf[TEST_BLOCK_SIZE];
  char buf1[80];
  char buf2[80];
  SHORTSIZ16 adcOverload, adcError;
  LONGSIZ32 actualCnt, phase, temp;
  LONGSIZ32 trigDelay[NUM_DELAYS];
  SHORTSIZ16 offset[4];
  FLOATSIZ64 trigLevel[3];

  trigDelay[0] = -1000; 
  trigDelay[1] = 0; 
  trigDelay[2] = 2049; 

  groupID = e1430_create_module_group(1, &la);
  if(groupID == 0) {
    return(-1);
  }

  error = e1430_reset_module(groupID);
  if(error) return(error);

  /* get adc values when offset DAC set at 0x400 and 0xC00 */
  error = e1430_set_analog_input(groupID, TEST_RANGE, E1430_COUPLING_DC,
	E1430_ANTIALIAS_ON, E1430_INPUT_HI_GROUND, E1430_INPUT_LO_FLOAT);
  if(error) return(error);

  error = e1430_set_data_format(groupID, E1430_DATA_TYPE_REAL, 
	E1430_DATA_SIZE_16, E1430_BLOCK_MODE, 
	TEST_BLOCK_SIZE, E1430_APPEND_STATUS_OFF);
  if(error) return(error);

  error = e1430_write_register_image(la, E1430_INPUT_OFFSET_REG, 0x400);
  if(error) return(error);
  
  e1430_pause(0.2);

  error = i1430_start_meas_and_wait(la);
  if(error) return(error);

  error = e1430_read_float32_data(la, buf, TEST_BLOCK_SIZE,
				&adcOverload, &adcError, &actualCnt);
  if(error) return(error);

  val0x400 = (FLOATSIZ64)buf[0];

  if(val0x400 > MAX_OFFSET || val0x400 < MIN_OFFSET) {
    (void)sprintf(buf1, "%lf", val0x400);
    (void)sprintf(buf2, "%lf to %lf", MIN_OFFSET, MAX_OFFSET);
    error = i1430_Error(ERR1430_OFFSET_DAC_BAD, buf1, buf2);
    if(error) return(error);
  }

  error = e1430_write_register_image(la, E1430_INPUT_OFFSET_REG, 0xC00);
  if(error) return(error);
   
  e1430_pause(0.2);

  error = i1430_start_meas_and_wait(la);
  if(error) return(error);

  error = e1430_read_float32_data(la, buf, TEST_BLOCK_SIZE, 
				&adcOverload, &adcError, &actualCnt);
  if(error) return(error);

  val0xC00 = (FLOATSIZ64)buf[0];	

  if(val0xC00 < -MAX_OFFSET || val0xC00 > -MIN_OFFSET) {
    (void)sprintf(buf1, "%lf", val0xC00);
    (void)sprintf(buf2, "%lf to %lf", -MAX_OFFSET, -MIN_OFFSET);
    error = i1430_Error(ERR1430_OFFSET_DAC_BAD, buf1, buf2);
    if(error) return(error);
  }

  
  /* test trigger disable and auto trigger */
  (void)sprintf(buf1, "%d", (LONGSIZ32)la);

  /* offset DAC near rail on negative side */
  error = e1430_write_register_image(la, E1430_INPUT_OFFSET_REG, 0xE00);
  if(error) return(error);
  
  /* disable triggering with auto trigger on */
  error = e1430_write_register_image(la, E1430_TRIGGER_SETUP_REG, 0x1000);
  if(error) return(error);

  error = e1430_arm_module(groupID);
  if(e1430_device_clear_flag) return(0);	/* SCPI issued a device clear */
  if(error) return(error);

  error = e1430_get_status(la, &data);
  if(error) return(error);
 
  if((data & E1430_MEAS_STATUS_STATE_MASK) != E1430_MEAS_STATUS_TRIG_STATE) {
    error = i1430_Error(ERR1430_FAIL_ENTER_TRIGGER, buf1, NULL);
    if(error) return(error);
  }
	   
  /* disable triggering with auto trigger off */
  error = e1430_write_register_image(la, E1430_TRIGGER_SETUP_REG, 0x1100);
  if(error) return(error);

  error = e1430_get_status(la, &data);
  if(error) return(error);

  if((data & E1430_MEAS_STATUS_STATE_MASK) != E1430_MEAS_STATUS_TRIG_STATE) {
    error = i1430_Error(ERR1430_ILLEGAL_TRIG_EXIT, NULL, NULL);
    if(error) return(error);
  }

  /* run offset DAC thru trigger point to try to cause trigger */
  error = e1430_write_register_image(la, E1430_INPUT_OFFSET_REG, 0x200);
  if(error) return(error);
  
  error = e1430_get_status(la, &data);
  if(error) return(error);
 
  if((data & E1430_MEAS_STATUS_STATE_MASK) != E1430_MEAS_STATUS_TRIG_STATE) {
    error = i1430_Error(ERR1430_ILLEGAL_TRIG_EXIT, NULL, NULL);
    if(error) return(error);
  }

  error = e1430_write_register_image(la, E1430_TRIGGER_SETUP_REG, 0x0100);
  if(error) return(error);

  error = e1430_get_status(la, &data);
  if(error) return(error);
 
  if((data & E1430_MEAS_STATUS_STATE_MASK) != E1430_MEAS_STATUS_TRIG_STATE) {
    error = i1430_Error(ERR1430_ILLEGAL_TRIG_EXIT, NULL, NULL);
    if(error) return(error);
  }

  error = e1430_write_register_image(la, E1430_TRIGGER_SETUP_REG, 0x0000);
  if(error) return(error);

  error = e1430_get_status(la, &data);
  if(error) return(error);

  if((data & E1430_MEAS_STATUS_STATE_MASK) == E1430_MEAS_STATUS_TRIG_STATE) {
    error = i1430_Error(ERR1430_FAIL_TRIG_EXIT, NULL, NULL);
    if(error) return(error);
  }

  error = e1430_write_register_image(la, E1430_TRIGGER_SETUP_REG, 0x1000);
  if(error) return(error);

  error = e1430_arm_module(groupID);
  if(e1430_device_clear_flag) return(0);	/* SCPI issued a device clear */
  if(error) return(error);

  error = e1430_get_status(la, &data);
  if(error) return(error);
 
  if((data & E1430_MEAS_STATUS_STATE_MASK) != E1430_MEAS_STATUS_TRIG_STATE) {
    error = i1430_Error(ERR1430_FAIL_ENTER_TRIGGER, buf1, NULL);
    if(error) return(error);
  }

  error = i1430_pull_sync(la, MEAS_CONTROL_NORMAL_MODE);
  if(error) return(error);
	   
  error = i1430_release_sync(la, MEAS_CONTROL_NORMAL_MODE);
  if(error) return(error);
	   
  error = e1430_get_status(la, &data);
  if(error) return(error);
 
  if((data & E1430_MEAS_STATUS_STATE_MASK) == E1430_MEAS_STATUS_TRIG_STATE) {
    error = i1430_Error(ERR1430_FAIL_TRIG_EXIT, buf1, NULL);
    if(error) return(error);
  }


  /* do trigger level test with slope. Use the offset DAC to cause transition */

  error = e1430_write_register_image(la, E1430_TRIGGER_SETUP_REG, 
	TRIGGER_SETUP_SOURCE_INT | TRIGGER_SETUP_INTERNAL_ADC |
	TRIGGER_SETUP_TRIG_AUTO_OFF); 
  if(error) return(error);

  error = e1430_set_data_format(groupID, E1430_DATA_TYPE_REAL, 
	E1430_DATA_SIZE_16, E1430_BLOCK_MODE, 
	TEST_BLOCK_SIZE, E1430_APPEND_STATUS_OFF);
  if(error) return(error);

  error = e1430_set_analog_input(groupID, TEST_RANGE, E1430_COUPLING_DC,
	E1430_ANTIALIAS_ON, E1430_INPUT_HI_GROUND, E1430_INPUT_LO_FLOAT);
  if(error) return(error);

  error = e1430_write_register_image(la, E1430_ADC_CONTROL_REG,
		ADC_CONTROL_DIAG_NORMAL | ADC_CONTROL_CAL_MODE_NORMAL);
  if(error) return(error);

  trigLevel[0] = val0x400/(TEST_RANGE); /* positive trigger */
  trigLevel[1] = 0.0;			/* zero trigger level */
  trigLevel[2] = val0xC00/(TEST_RANGE); /* negative trigger */

  offset[0] = 0x200;		/* a point on each side of each trigLevel[] */
  offset[1] = 0x600;
  offset[2] = 0xA00;
  offset[3] = 0xE00;

 
  error = e1430_write_register_image(la, E1430_INPUT_OFFSET_REG, offset[0]);
  if(error) return(error);
  
  e1430_pause(0.1);

  (void)sprintf(buf1, "for ADC triggering");

  for(k=0; k<3; k++) {	/* slope negative, should be no trigger */
    error = check_slope_trigger(groupID, E1430_TRIGGER_SOURCE_ADC, trigLevel[k],
	E1430_TRIGGER_SLOPE_POS, offset[k+1], &triggered);
    if(error) return(error);

    if(triggered) {
      error = i1430_Error(ERR1430_WRONG_TRIG_SLOPE, buf1, NULL);
      if(error) return(error);
    }
  }
  
  for(k=2; k>=0; k--) {	/* slope positive, should trigger */
    error = check_slope_trigger(groupID, E1430_TRIGGER_SOURCE_ADC, trigLevel[k],
	E1430_TRIGGER_SLOPE_POS, offset[k], &triggered);
    if(error) return(error);

    if(!triggered) {
      error = i1430_Error(ERR1430_FAIL_TRIG_SLOPE, buf1, NULL);
      if(error) return(error);
    }
  }

  for(k=0; k<3; k++) {	/* slope negative, should trigger */
    error = check_slope_trigger(groupID, E1430_TRIGGER_SOURCE_ADC, trigLevel[k],
	E1430_TRIGGER_SLOPE_NEG, offset[k+1], &triggered);
    if(error) return(error);

    if(!triggered) {
      error = i1430_Error(ERR1430_FAIL_TRIG_SLOPE, buf1, NULL);
      if(error) return(error);
    }
  }

  for(k=2; k>=0; k--) {	/* slope positive, should not trigger */
    error = check_slope_trigger(groupID, E1430_TRIGGER_SOURCE_ADC, trigLevel[k],
	E1430_TRIGGER_SLOPE_NEG, offset[k], &triggered);
    if(error) return(error);

    if(triggered) {
      error = i1430_Error(ERR1430_WRONG_TRIG_SLOPE, buf1, NULL);
      if(error) return(error);
    }
  }


  /* test mag trigger */

  trigLevel[0] = 20 * log10(fabs(val0x400/TEST_RANGE)); 
  trigLevel[1] = 20 * log10(fabs(val0xC00/TEST_RANGE));

  offset[0] = 0x200;		/* a point on each side of each trigLevel[] */
  offset[1] = 0x800;
  offset[2] = 0xe00;

  error = e1430_write_register_image(la, E1430_INPUT_OFFSET_REG, offset[1]);
  if(error) return(error);
  
  e1430_pause(0.2);

  (void)sprintf(buf1, "for MAG triggering");

  /* should trigger going from lower to higher mag */
  error = check_slope_trigger(groupID, E1430_TRIGGER_SOURCE_MAG, trigLevel[0],
	E1430_TRIGGER_SLOPE_POS, offset[0], &triggered);
  if(error) return(error);

  if(!triggered) {
    error = i1430_Error(ERR1430_FAIL_TRIG_SLOPE, buf1, NULL);
    if(error) return(error);
  }

  /* should not trigger going from higher to lower mag */
  error = check_slope_trigger(groupID, E1430_TRIGGER_SOURCE_MAG, trigLevel[0],
	E1430_TRIGGER_SLOPE_POS, offset[1], &triggered);
  if(error) return(error);

  if(triggered) {
    error = i1430_Error(ERR1430_WRONG_TRIG_SLOPE, buf1, NULL);
    if(error) return(error);
  }

  error = e1430_write_register_image(la, E1430_INPUT_OFFSET_REG, offset[2]);
  if(error) return(error);
  
  e1430_pause(0.2);

  /* should trigger going from higher to lower mag */
  error = check_slope_trigger(groupID, E1430_TRIGGER_SOURCE_MAG, trigLevel[1],
	E1430_TRIGGER_SLOPE_NEG, offset[1], &triggered);
  if(error) return(error);

  if(!triggered) {
    error = i1430_Error(ERR1430_FAIL_TRIG_SLOPE, buf1, NULL);
    if(error) return(error);
  }

  /* should not trigger going from lower to higher mag */
  error = check_slope_trigger(groupID, E1430_TRIGGER_SOURCE_MAG, trigLevel[1],
		 
	E1430_TRIGGER_SLOPE_NEG, offset[2], &triggered);
  if(error) return(error);

  if(triggered) {
    error = i1430_Error(ERR1430_WRONG_TRIG_SLOPE, buf1, NULL);
    if(error) return(error);
  }


  /* do pre/post trigger test by comparing passtags received for multi-pass
   * data with passtags expected from the captured trigger phase 
   */
  
  /* multipass  >= pass 1 , data point size = 8 bytes for consistent trigger */
  error = e1430_set_data_format(groupID, E1430_DATA_TYPE_COMPLEX, 
	E1430_DATA_SIZE_32, E1430_BLOCK_MODE, 
	TEST_BLOCK_SIZE, E1430_APPEND_STATUS_OFF);
  if(error) return(error);

  error = e1430_set_trigger_source(groupID, E1430_TRIGGER_SOURCE_AUTO); 
  if(error) return(error);

  error = e1430_set_decimation_filter(groupID, 2, E1430_DECIMATION_OFF, 
				E1430_MULTIPASS, E1430_PASS_TAG_32);
  if(error) return(error);

  for(k = 0; k < NUM_DELAYS; k++) {  /* for all trigger delays in trigDelay[] */

    error = e1430_set_trigger_delay(groupID, trigDelay[k]);
    if(error) return(error);

    /* start the measurement and wait for data to be ready */
    error = i1430_start_meas_and_wait(la);
    if(error) return(error);
  
    error = i1430_get_trigger_phase_bits(la, &phase);
    if(error) return(error);

/*printf("delay = %ld, phase = %lX\n", trigDelay[k], phase); */
    phase += (1L << 25) + PHASE_DELAY; 	/* subtract static phase delay */
    if(trigDelay[k] != 0L) phase += 1; 
    
    phase += trigDelay[k];	/* add expected trigger delay */

    phase %= (1L << 25);

    /* check passtags against passtag calculated from expected trigger delay */
    for(i=0; i<TEST_BLOCK_SIZE; i++) {
      /* throw away first 3 words to get to passtag */
      e1430_read_register_card(la, E1430_HP_SEND_DATA_REG, &data);
      e1430_read_register_card(la, E1430_HP_SEND_DATA_REG, &data);
      e1430_read_register_card(la, E1430_HP_SEND_DATA_REG, &data);
      /* get pass tag in 4nd word */
      error = e1430_read_register_card(la, E1430_HP_SEND_DATA_REG, &data);
      if(error) return(error);
      
      temp = phase++;	/* increment trigger phase to calculate next passtag*/	
 
      /* bit position of first zero + 1 is the calculated passtag */
      for(j=1; j<32; j++) {  	/* find first zero on right */
        if(temp%2 == 0) break;
        temp >>= 1;
      }
      
      if(j != (data & 0x1F)) {		/* if passtag not correct */
        (void)sprintf(buf1, "expected passtag = %d", (LONGSIZ32)j);
        (void)sprintf(buf2, "got passtag = %d", (LONGSIZ32)(data & 0x1F));
        error = i1430_Error(ERR1430_FAIL_TRIG_DELAY, buf1, buf2);
        if(error) return(error);
      } 
    }		/* for i < TEST_BLOCK_SIZE */
  }		/* for all trigDelay[] */



  /* wrap (reread) mode test */

  error = e1430_reset_module(groupID);
  if(error) return(error);

  /* block mode, complex 16-bit data */
  error = e1430_set_data_format(groupID, E1430_DATA_TYPE_COMPLEX,
		E1430_DATA_SIZE_16, E1430_BLOCK_MODE, 4096L,
		E1430_APPEND_STATUS_OFF);
  if(error) return(error);

  /* zoom to Fs/1000*/
  error = e1430_set_center_frequency(groupID, .001);
  if(error) return(error);

  /* output constant from ADC set to rail */
  error = e1430_write_register_image(la, E1430_ADC_CONTROL_REG, 0x3E);
  if(error) return(error);

  error = e1430_write_register_image(la, E1430_TIMING_SETUP_REG, 0x40);
  if(error) return(error);

  /* auto trigger */
  error = e1430_set_trigger_mode(groupID, E1430_TRIGGER_SOURCE_AUTO,
		0L, 0.0, E1430_TRIGGER_SLOPE_POS); 
  if(error) return(error);

  /* reread bit set */
  error = e1430_read_register_image(la, E1430_TRIGGER_BLOCKSIZE_REG, &data);
  if(error) return(error);

  data |= TRIGGER_BLOCKSIZE_REREAD_ON;
  error = e1430_write_register_image(la, E1430_TRIGGER_BLOCKSIZE_REG, data);
  if(error) return(error);

  e1430_pause(.1);		/* wait for front end to settle */

  /* start meas */
  error = i1430_start_meas_and_wait(la);
  if(error) return(error);

  addr = (USHORTSIZ16 *)e1430_get_register_address(la, E1430_HP_SEND_DATA_REG); 

  E1430_TRY 

    firstx = iwpeek(addr);		/* get first two points in block */
    firsty = iwpeek(addr);
    E1430_CHECK_BERR

    /* enough reads to wrap end of block and be positioned at start of data */ 
    for(e1430_i=1; e1430_i< 4096; e1430_i++) { 
      x = iwpeek(addr);
      y = iwpeek(addr);
    }
    E1430_CHECK_BERR

    x = iwpeek(addr);			/* get two points after wrap */
    y = iwpeek(addr);
    E1430_CHECK_BERR
    if(x != firstx || y != firsty) {
      (void)sprintf(buf1, "incorrect wrap at end of block");
      return(i1430_Error(ERR1430_REREAD_FAILURE, buf1, NULL));
    }

  E1430_RECOVER {
    (void)sprintf(buf1, "bus error reading beyond end of block");
    return(i1430_Error(ERR1430_REREAD_FAILURE, buf1, NULL));
  }

  error = e1430_delete_module_group(groupID);
  return(error);
}              
